#ifndef __HELPER_HPP__
#define __HELPER_HPP__

#include <iostream>
#include <vector>
#include <string>
#include <sstream>
#include <random>
#include <iomanip>
#include <atomic>
#include <fstream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sqlite3.h>
#include "logger.hpp"

namespace mq
{
    /*数据库操作类*/
    class SqliteHelper
    {
    private:
        typedef int (*SqliteCallback)(void *, int, char **, char **);

    public:
        SqliteHelper(const std::string dbfile) : _dbfile(dbfile) {}

        /*指定打开方式打开数据库文件*/
        bool open(int flags = SQLITE_OPEN_FULLMUTEX)
        {
            int ret = sqlite3_open_v2(_dbfile.c_str(), &_pdb, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | flags, nullptr);
            if (ret != SQLITE_OK)
            {
                ELOG("创建/打开sqlite数据库失败: %s", sqlite3_errmsg(_pdb));
                return false;
            }
            return true;
        }

        /*执行sql语句*/
        bool exec(const std::string &query, SqliteCallback cb, void *arg)
        {
            int ret = sqlite3_exec(_pdb, query.c_str(), cb, arg, nullptr);
            if (ret != SQLITE_OK)
            {
                ELOG("%s \n语句执行失败: %s", query.c_str(), sqlite3_errmsg(_pdb));
                return false;
            }
            return true;
        }

        void close()
        {
            if (_pdb != nullptr)
                sqlite3_close_v2(_pdb);
        }

    private:
        std::string _dbfile;
        sqlite3 *_pdb;
    };

    /*字符串操作类*/
    class StrHelper
    {
    public:
        static size_t split(const std::string &str, const std::string &seq, std::vector<std::string> *arry)
        {
            size_t index = 0;
            size_t pos = 0;
            while (index < str.size())
            {
                pos = str.find(seq, index);
                if (pos == std::string::npos)
                {
                    arry->push_back(str.substr(index));
                    break;
                }
                if (index == pos)
                {
                    index = pos + seq.size();
                    continue;
                }
                arry->push_back(str.substr(index, pos - index));
                index = pos + seq.size();
            }
            return arry->size();
        }
    };

    /*UUID生成类*/
    class UUIDHelper
    {
    public:
        static std::string uuid()
        {
            std::random_device rd;
            std::mt19937_64 generator(rd());                         // 种下种子生成随机数
            std::uniform_int_distribution<int> distribution(0, 255); // 指定随机数范围
            std::stringstream ss;
            for (int i = 0; i < 8; i++)
            {
                ss << std::setw(2) << std::setfill('0') << std::hex << distribution(generator); // 生成宽度为2,不足用0填充的十六进制数
                if (i == 3 || i == 5 || i == 7)
                    ss << "-";
            }

            // 生成自增长的序号
            static std::atomic<size_t> seq(1);
            size_t num = seq.fetch_add(1);
            for (int i = 7; i >= 0; i--)
            {
                ss << std::setw(2) << std::setfill('0') << std::hex << (num >> (i * 8) & 0xff);
                if (i == 6)
                    ss << "-";
            }

            return ss.str();
        }
    };

    /*文件操作类*/
    class FileHelper
    {
    public:
        FileHelper(const std::string &filename) : _filename(filename) {}

        /*判断文件是否存在*/
        bool exists()
        {
            struct stat st;
            bzero(&st, sizeof(st));
            if (stat(_filename.c_str(), &st) < 0)
                return false;
            return true;
        }

        /*获取文件大小*/
        size_t size()
        {
            struct stat st;
            bzero(&st, sizeof(st));
            if (stat(_filename.c_str(), &st) < 0)
                return 0;
            return st.st_size;
        }

        /*从指定偏移量处读取指定长度的内容*/
        bool read(char *buf, size_t offset, size_t len)
        {
            std::ifstream ifs(_filename, std::ios::in | std::ios::binary);
            if (ifs.is_open() == false)
            {
                ELOG("%s 文件打开失败", _filename.c_str());
                return false;
            }

            ifs.seekg(offset, std::ios::beg);
            ifs.read(buf, len);
            if (ifs.good() == false)
            {
                ELOG("%s 文件读取失败", _filename.c_str());
                ifs.close();
                return false;
            }

            ifs.close();
            return true;
        }

        /*从文件中读取全部内容*/
        bool read(std::string &body)
        {
            size_t fsize = size();
            body.resize(fsize);
            return read(&body[0], 0, fsize);
        }

        /*从指定偏移量处写入指定长度的内容*/
        bool write(const char *buf, size_t offset, size_t len)
        {
            // 以读写打开，单纯写打开无法偏移
            std::fstream fs(_filename, std::ios::in | std::ios::out | std::ios::binary);
            if (fs.is_open() == false)
            {
                ELOG("%s 文件打开失败", _filename.c_str());
                return false;
            }

            fs.seekp(offset, std::ios::beg);
            fs.write(buf, len);
            if (fs.good() == false)
            {
                ELOG("%s 文件写入失败", _filename.c_str());
                fs.close();
                return false;
            }
            return true;
        }

        /*将内容从开始位置写入*/
        size_t write(const std::string &body)
        {
            return write(body.c_str(), 0, body.size());
        }

        /*重命名*/
        bool rename(const std::string &new_name)
        {
            return (::rename(_filename.c_str(), new_name.c_str()) == 0);
        }

        /*创建文件*/
        static bool createFile(const std::string &filename)
        {
            std::fstream ofs(filename, std::ios::binary | std::ios::out);
            if (ofs.is_open() == false)
            {
                ILOG("%s 文件不存在,创建文件", filename.c_str());
                return false;
            }
            ofs.close();
            return true;
        }

        /*删除文件*/
        static bool removeFile(const std::string &filename)
        {
            return (::remove(filename.c_str()) == 0);
        }

        /*获取路径的中的父目录*/
        static std::string parentDirectory(const std::string &filename)
        {
            size_t pos = filename.find_last_of("/");
            if (pos == std::string::npos)
                return "./";
            return filename.substr(0, pos);
        }

        /*创建目录,考虑到多级目录情况*/
        static bool createDirectory(const std::string &pathname)
        {
            size_t index = 0;
            size_t pos = 0;
            while (index < pathname.size())
            {
                pos = pathname.find("/", index);
                if (pos == std::string::npos)
                {
                    return (::mkdir(pathname.c_str(), 0775) == 0);
                }

                std::string sub_path = pathname.substr(0, pos);
                int ret = ::mkdir(sub_path.c_str(), 0775);
                if (ret < 0 && errno != EEXIST)
                {
                    ELOG("创建目录 %s 失败: %s", sub_path.c_str(), strerror(errno));
                    return false;
                }
                index = pos + 1;
            }

            return true;
        }
        static bool removeDirectory(const std::string &path)
        {
            std::string cmd = "rm -rf " + path;
            return (::system(cmd.c_str()) != -1);
        }

    private:
        std::string _filename;
    };
}

#endif